package AliDiepPR.Util;

import java.util.Vector;

import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;

public class ImageProcessing {
	public static int grayScale(int argb) {
		int arg = 0, temp = 0;
		int color[] = new int[3];
		for (int i = 0; i < 3; i++) {
			temp = 0;
			for (int j = 0; j < 8; j++) {
				temp = (temp << j) ^ (argb & 1);
				argb >>= 1;
			}
			color[i] = 0;
			for (int j = 0; j < 8; j++) {
				color[i] = (color[i] << j) ^ (temp & 1);
				temp >>= 1;
			}
		}
		arg = (int) (color[0] * 0.1f + color[1] * 0.7f + color[2] * 0.2f);
		return arg;
	}

	public static Rect findBorder(Size size, Bitmap img) {
		Rect res = new Rect();

		int wid = img.getWidth();
		int hei = img.getHeight();

		int left = wid, right = 0;
		int top = hei, bottom = 0;

		for (int y = 0; y < hei; y++)
			for (int x = 0; x < wid; x++) {
				int c = img.getPixel(x, y);
				c = grayScale(c);
				if (c < 250) {
					if (x < left)
						left = x;
					if (x > right)
						right = x;
					if (y < top)
						top = y;
					if (y > bottom)
						bottom = y;
				}
			}

		int bou = 5;
		left -= bou;
		if (left < 0)
			left = 0;
		top -= bou;
		if (top < 0)
			top = 0;
		right += bou;
		if (right > wid)
			right = hei;
		bottom += bou;
		if (bottom > hei)
			bottom = hei;

		if (right - left + 1 < size.Width) {
			int w = right - left + 1;
			left -= (size.Width - w) / 2;
			right += (size.Width - w) / 2 + 1;

			if (left < 0)
				left = 0;
			if (right > wid)
				right = wid;
		}

		if (bottom - top + 1 < size.Height) {
			int h = bottom - top + 1;
			top -= (size.Height - h) / 2;
			bottom += (size.Height - h) / 2 + 1;
			if (top < 0)
				top = 0;
			if (bottom > hei)
				bottom = hei;
		}

		res.set(left, top, right, bottom);

		return res;
	}

	public static int[][] getBinaryImage(Bitmap bitmap) {
		int width = bitmap.getWidth();
		int height = bitmap.getHeight();
		int[][] result = new int[height][width];
		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				int temp = bitmap.getPixel(j, i);
				temp = ImageProcessing.grayScale(temp);
				if (temp >= 250) {
					result[i][j] = 0;
				} else {
					result[i][j] = 1;
				}
			}
		}
		return result;
	}

	public static int[][] getZone(Size size, Bitmap image) {
		int[][] img = getBinaryImage(image);
		int wid = image.getWidth();
		int hei = image.getHeight();

		int[] hisRow = new int[hei];
		int[] hisCol = new int[wid];

		for (int i = 0; i < hei; i++)
			for (int j = 0; j < wid; j++) {
				hisRow[i] += img[i][j];
				hisCol[j] += img[i][j];
			}

		Vector<Point> indexHisCol = getVectorPoint(hisCol);
		Vector<Point> indexHisRow = getVectorPoint(hisRow);

		wid = indexHisCol.size();
		hei = indexHisRow.size();

		// just for 1 row
		// extend for n row later
		int[][] res = new int[wid][];
		for (int c = 0; c < wid; c++) {
			Point infoRow = (Point) indexHisRow.elementAt(0);
			Point infoCol = (Point) indexHisCol.elementAt(c);

			int[][] zone = scaleZone(size, new Point[] { infoRow, infoCol },
					img);

			res[c] = new int[zone.length * zone[0].length + 2];
			res[c][0] = zone.length;
			res[c][1] = zone[0].length;
			for (int i = 0; i < zone.length; i++)
				for (int j = 0; j < zone[0].length; j++)
					res[c][2 + i * zone[0].length + j] = zone[i][j];
		}

		return res;
	}

	public static int[][] scaleZone(Size size, Point[] index, int[][] image) {
		int[][] res = new int[size.Height][size.Width];

		int hei = index[0].y - index[0].x + 1;
		int wid = index[1].y - index[1].x + 1;
		int edge = hei > wid ? hei : wid;

		int[][] rectangle = new int[edge][edge];
		int ii = index[0].x, jj = index[1].x;
		for (int i = (edge - hei) / 2; i < (edge + hei) / 2; i++) {
			jj = index[1].x;
			for (int j = (edge - wid) / 2; j < (edge + wid) / 2; j++) {
				if (ii > index[0].y)
					ii = index[0].y;
				if (jj > index[1].y)
					jj = index[1].y;
				rectangle[i][j] = image[ii][jj];
				jj++;
			}
			ii++;
		}

		int unit = edge / size.Width;
		for (int i = 0; i < edge; i++)
			for (int j = 0; j < edge; j++) {
				ii = i / unit;
				if (ii >= size.Height) ii = size.Height-1;
				jj = j / unit;
				if (jj >= size.Width) jj = size.Width-1;
				if (res[ii][jj] == 0)
					res[ii][jj] = rectangle[i][j];
			}

		return res;
	}

	private static Vector<Point> getVectorPoint(int[] histogram) {
		int i = 0, j = 0;
		Vector<Point> res = new Vector<Point>();
		int wid = histogram.length;
		while (i < wid) {
			if (histogram[i] > 0) {
				j = i;
				while (histogram[j] > 0 && j < wid)
					j++;
				res.add(new Point(i, j - 1));
				i = j - 1;
			}
			i++;
		}
		return res;
	}

	public static float[][] ConvertToBinary(Bitmap source) {
		int hei = source.getHeight();
		int wid = source.getWidth();
		float[][] ret = new float[hei][];
		for (int y = 0; y < hei; y++) {
			ret[y] = new float[wid];
			for (int x = 0; x < wid; x++) {
				int c = source.getPixel(x, y);
				c = grayScale(c);
				if (c > 250)
					ret[y][x] = 0f;
				else
					ret[y][x] = 1.0f;
			}
		}
		return ret;
	}

	public static float[] zoneSampling(float[][] source) {
		int wid = source[0].length;
		int hei = source.length;
		float[] res = new float[wid * hei];

		for (int i = 0; i < hei; i++)
			for (int j = 0; j < wid; j++)
				res[i * hei + j] = source[i][j];

		return res;
	}

	public static float[] zoneSampling(int sizeZone, float[][] source) {
		int wid = source[0].length;
		int hei = source.length;

		int total = 0, y, x, count;
		int[][] a = new int[hei][];

		for (int i = 0; i < hei; i++)
			a[i] = new int[wid];

		if (source[0][0] == 1)
			a[0][0] = 1;
		for (y = 1; y < hei; y++) {
			a[y][0] = a[y - 1][0];
			if (source[y][0] == 1.0f)
				a[y][0]++;
		}
		for (x = 1; x < wid; x++) {
			a[0][x] = a[0][x - 1];
			if (source[0][x] == 1.0f)
				a[0][x]++;
		}

		for (y = 1; y < hei; y++)
			for (x = 1; x < wid; x++) {
				a[y][x] = a[y - 1][x] + a[y][x - 1] - a[y - 1][x - 1];
				if (source[y][x] == 1.0f)
					a[y][x]++;
			}

		total = a[hei - 1][wid - 1];

		float[] res = new float[hei / sizeZone * wid / sizeZone];
		count = 0;
		res[count] = a[sizeZone - 1][sizeZone - 1] * 1.0f / total;
		count++;
		for (x = sizeZone + 1; x < wid; x += sizeZone) {
			res[count] = (a[sizeZone - 1][x] - a[sizeZone - 1][x - sizeZone])
					* 1.0f / total;
			count++;
		}

		for (y = sizeZone + 1; y < hei; y += sizeZone) {
			res[count] = (a[y][sizeZone - 1] - a[y - sizeZone][sizeZone - 1])
					* 1.0f / total;
			count++;
		}

		for (y = sizeZone + 1; y < hei; y += sizeZone)
			for (x = sizeZone + 1; x < wid; x += sizeZone) {
				res[count] = (a[y][x] - a[y - sizeZone][x] - a[y][x - sizeZone] + a[y
						- sizeZone][x - sizeZone])
						* 1.0f / total;
				count++;
			}

		return res;
	}

	public static Bitmap reSize(Size size, Bitmap bitmapOrg) {
		int width = bitmapOrg.getWidth();
		int height = bitmapOrg.getHeight();
		int newWidth = size.Width;
		int newHeight = size.Height;

		float scaleWidth = ((float) newWidth) / width;
		float scaleHeight = ((float) newHeight) / height;
		Matrix matrix = new Matrix();
		matrix.postScale(scaleWidth, scaleHeight);
		Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0, width,
				height, matrix, true);
		return resizedBitmap;
	}

	public static double[] DoubleBinaryTargetArray(int position, int size) {
		double[] result = new double[size];
		for (int i = 0; i < size; i++) {
			result[i] = 0;
		}
		result[position] = 1;
		return result;
	}

	public static double[] DoubleBipolarTargetArray(int position, int size) {
		double[] result = new double[size];
		for (int i = 0; i < size; i++) {
			result[i] = -1;
		}
		result[position] = 1;
		return result;
	}

	public static double[] flattenIntMatrix(int[][] ImageMatrix) {
		int h = ImageMatrix.length;
		int w = ImageMatrix[0].length;
		double[] result = new double[w * h];
		for (int i = 0; i < h; i++) {
			for (int j = 0; j < w; j++) {
				result[i * w + j] = ImageMatrix[i][j];
			}
		}
		return result;
	}

	public static double[] normalizeArray(double[] input) {
		int l = input.length;
		double[] result = new double[l];
		for (int i = 0; i < l; i++) {
			if (input[i] >= 1) {
				result[i] = 1;
			} else {
				result[i] = -1;
			}
		}
		return result;
	}

	public static int getPositionFromResult(double[] output) {
		int result = 0;
		for (int i = 0; i < output.length; i++) {
			if (output[i] == 1) {
				result = i;
				break;
			}
		}
		return result;
	}

}
